package at.ac.tuwien.dse.health.admin

import at.ac.tuwien.dse.health.admin.http.RequestMapping
import at.ac.tuwien.dse.health.admin.jdbc._
import java.sql.{Connection, DriverManager}
import java.util.ResourceBundle
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
import scala.io.Source
import scala.xml.Node


object HealthAdminServlet {
	val conf = ResourceBundle getBundle "database"

	/** Establishes a database connection */
	def createConnection: Connection = {
		def getPostgreSqlDataSource = {
			import org.cloudfoundry.runtime.env._
			import org.cloudfoundry.runtime.service.relational._

			val env = new CloudEnvironment
			val serviceInfo = env getServiceInfos classOf[RdbmsServiceInfo]
			if (serviceInfo.isEmpty) null
			else {
				val delegate = classOf[RdbmsServiceInfo].getDeclaredField("delegate")
				delegate.setAccessible(true)
				val postgresqlInfo = delegate.get(serviceInfo.get(0)).asInstanceOf[PostgresqlServiceInfo]
				(new PostgresqlServiceCreator() createSingletonService postgresqlInfo).service.getConnection
			}
		}

		def getHsqlDataSource: Connection = {
			Class forName (conf getString "driver")
			val conn = DriverManager getConnection(conf getString "url", conf getString "username", conf getString "password")

			// Create the initial schema if necessary
			val jdbcTemplate = new JdbcTemplate(conn)
			val source = Source fromInputStream (getClass getClassLoader() getResourceAsStream "schema.sql")
			source getLines() mkString("") split ';' foreach(new PreparedStatementHolder(jdbcTemplate, _).update())

			conn
		}

		try {
			val dataSource = getPostgreSqlDataSource
			if (dataSource == null)	println("Cannot establish connection to PostgreSQL database")
			if (dataSource != null) dataSource else getHsqlDataSource
		} catch {
			case e: Throwable => e printStackTrace()
			throw e
		}
	}
}

// @WebServlet(name = "HealthAdminServlet", urlPatterns = Array("/admin/*"), loadOnStartup = 1)
class HealthAdminServlet extends DispatcherServlet with JdbcSupport {

	var conn: Connection = HealthAdminServlet.createConnection
	implicit val jdbcTemplate: JdbcTemplate = new JdbcTemplate(conn)

	override def applyTemplate(node: Node) = {
<html>
	<head>
		<title>HEALTH - Admin Portal</title>
		<link href="../css/bootstrap.css" rel="stylesheet"/>
		<link href="../css/style.css" rel="stylesheet"/>
	</head>
	<body>
		<div class="navbar navbar-fixed-top">
			<div class="navbar-inner">
				<div class="container-fluid">
					<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
						<span class="icon-bar"></span>
					</button>
					<a class="brand" href="#">{"HEALTH Admin Portal"}</a>
					<div class="nav-collapse collapse">
						<p class="navbar-text pull-right">
							{for {entry <- requestMapping if entry._2.isPublic} yield <span>{" | "}<a href={entry._1}>{entry._1}</a></span>}
							<img src="../images/database.png" width="72"/>
						</p>
					</div>
				</div>
			</div>
		</div>
		{node}
		<footer>
			<p>&copy; Bernhard Nickel, Gregor Schauer, Dominik Strasser - 2013</p>
		</footer>
	</body>
</html>
	}

	@RequestMapping("")
	private[admin] def index(req: HttpServletRequest, resp: HttpServletResponse) = {
<h1>Welcome</h1>
	}

	@RequestMapping("overview")
	def overview(req: HttpServletRequest, resp: HttpServletResponse) = {
		val rs = conn.getMetaData getTables(null, HealthAdminServlet.conf getString "schema", null, null)
		val rowMapper = new SimpleRowMapper[String](3)

<div>
	<button class="btn btn-danger btn-large" onclick="window.location.href='reset'">Reset Database</button>
	<p/>
	{for {r <- rowMapper.mapRows(rs)} yield printTable(r)}
</div>
	}

	@RequestMapping("reset")
	def reset(req: HttpServletRequest, resp: HttpServletResponse): Node = {
		conn.setAutoCommit(false)

		// Delete
		/*
		// Note that the following code is more generic but works only if there are no constraints.
		val rs = conn.getMetaData getTables(null, HealthAdminServlet.conf getString "schema", null, null)
		while (rs.next()) s"DELETE FROM ${rs getString 3}" update()
		 */
		var source = Source fromInputStream (getClass getClassLoader() getResourceAsStream "clean.sql")
		source getLines() mkString("") split ';' foreach(_ update())

		// Populate
		source = Source fromInputStream (getClass getClassLoader() getResourceAsStream "init.sql")
		source getLines() mkString("") split ';' foreach(_ update())
		conn.commit()

<p>
	<div class="progress progress-success" style="width: 100%; font-size: 1.6em; color: #ffffff; height: 2em;">
		<div class="bar-success" style="line-height: 2em; padding-left: 1em;">Database reset successfully</div>
	</div>
	<a href="overview">Back to Overview</a>
</p>
	}

	def printTable(name: String) = try {
		val rs = f"SELECT * FROM $name"
		val metaData = rs.getMetaData
		val rows: List[List[Any]] = new ListRowMapper mapRows rs
<h3 class="text-info">{name}</h3>
<div>
	<table class="table table-striped table-bordered table-hover table-condensed">
		<tr>{for {col <- 1 to metaData.getColumnCount} yield <th>{metaData getColumnName col}</th>}</tr>
		{for {row <- rows} yield <tr>
			{for {col <- row} yield <td>{col}</td>}
		</tr>}
	</table>
</div><p/>
	} catch {
		case e: Throwable => <h3 class="text-error">{name}</h3>
	}
}
